<script setup lang="ts">
// 多容器改变大小
import { IBox } from "./inter"
import { ref, watch, computed, onMounted, reactive, defineComponent, h, useSlots } from "vue"
import { useMousePressed, useMouse, useElementSize, UseElementSizeReturn } from "@vueuse/core"
import { sum } from "lodash-es";
// import { BoxScroll } from "./index"

const props = withDefaults(defineProps<IBox.ResizesProps>(), {
    direction: "horizontal",
    boxs: () => ([])
})

const { boxs, direction,lockBox,lockItems } = props;
const isHorizontal = direction == 'horizontal';
const propName = isHorizontal ? 'width' : 'height'
const boxRef = ref<HTMLDivElement>();
const { x, y } = useMouse({ target: boxRef })
const sizes: UseElementSizeReturn[] = [];
const elems = new Array<HTMLElement>()
const cxy = ref(-1)
const cs = ref<-1|number[]>(-1)
const ci = ref<-1|number[]>(-1)
// 计算每次的变化量
const cd = computed(() => cxy.value > -1 ? isHorizontal ? x.value - cxy.value : y.value - cxy.value : -1) // 变化量
// 计算最小值
const ms = computed(() => {
    if(ci.value != -1 && ci.value.length == 2){
        return ci.value.map(i => {
            const cs = window.getComputedStyle(elems[i]);
            const mw = Number(cs.minWidth?.replace(/\D*$/g,'')) || 0;
            const mh = Number(cs.minHeight?.replace(/\D*$/g,'')) || 0;
            return isHorizontal ? mw : mh;
        })
        // return ci.value.map(i => isHorizontal ? Number(window.getComputedStyle(elems[i]).minWidth) || 0 : Number(window.getComputedStyle(elems[i]).minHeight) || 0)
    }
    return [0];
})
const cms = computed(() => (cs.value != -1 && cs.value.length == 2) ? sum(cs.value) : -1) // 变化前的两个容器总大小
// const cSize = computed(() => ci.value > -1 ? isHorizontal ? sizes[ci.value]?.width.value : sizes[ci.value]?.height.value : -1)
const cStyle = computed(() => {
    if(cs.value != -1){
        let ns = cs.value.map((v,i) => v + (i * -2 + 1) * cd.value).map((v,i) => v < ms.value[i] ? ms.value[i] : v);

        if(ns.length == 2 && sum(ns) != cms.value){
            ns = ns.map((v,i) => {
                return v != ms.value[i] ? cms.value - ms.value[(i - 1) * -1] : v
            })
        }
        
        return ns.map((v) => `flex:none;${propName}:${v}px`);
    }
    return ''
})
const defaultStyles = computed(() => {
    return boxs.map(({ size, minSize, maxSize }) => {
        let s = 'flex:1;'
        if (size) {
            s = `${propName}:${size};`
        }
        if (minSize) {
            s += `min-${propName}:${minSize};`
        }
        if (maxSize) {
            s += `max-${propName}:${maxSize};`
        }
        return s;
    })
})
const boxStyle = reactive([...defaultStyles.value])
//
const slots = useSlots();
const defaultNodes = computed(() => {
    const nodes = slots?.default?.()
    return nodes || []
})
const len = computed(() => defaultNodes.value.length)
//
watch([x, y], () => {
    if (cStyle.value && cStyle.value.length > 0 && ci.value != -1) {
        let t = 0;
        for(const i of ci.value){
            boxStyle[i] = (defaultStyles.value[i] || '') + cStyle.value[t++]
        }
    }
})


const handlePressed = (isPressed: boolean, index: number|number[]) => {
    ci.value = isPressed ? new Array<number>().concat(index) : -1
    cs.value = ci.value != -1 ? ci.value.map(i => isHorizontal ? sizes[i].width.value : sizes[i].height.value) : -1
    cxy.value = isPressed ? isHorizontal ? x.value : y.value : -1;
}

const handleBoxInit = (index: number, size: UseElementSizeReturn,elem:HTMLElement) => {
    sizes[index] = size;
    // minSizes[index] = minSize
    elems[index] = elem
    const style = (defaultStyles.value[index] || '') + `flex:none;${propName}:${isHorizontal ? size.width.value : size.height.value}px`
    boxStyle[index] = style;
}
//
const BaseBox = defineComponent((props, ctx) => {
    const { index, node } = props;
    const item = ref();
    const size = useElementSize(item)
    //
    const render = () => h(node, { ref: e => item.value = e, class: `flex-1 relative` })
    //
    onMounted(() => {
        const e = item.value;
        ctx.emit('init', index, size,e)
    })
    return render;
}, { props: ["index", "node"], emits: ['init'] })

const BaseLine = defineComponent((props, ctx) => {
    const { index, isHorizontal,lockBox,lockItems } = props;
    const el = ref()
    const et = ref();
    const { pressed:elp } = useMousePressed({ target: el });
    const { sourceType:ets } = useMousePressed({ target: et });
    watch(elp, (v) => {
        let args = null;
        if(ets.value == null){
            args = lockBox ? null : index;
        }
        else{
            args = lockItems ? null : [index,index + 1]
        }
        if(args != null){
            ctx.emit("pressed", v, args) 
        }
    })
    const render = () => h('div', { ref: e => el.value = e, class: `_line relative z-99 bg-#eee ${isHorizontal ? 'w-2 h-full cursor-ew-resize' : 'h-2 w-full cursor-ns-resize'} ${lockBox ? 'is-locked' : ''}` },
        h('i',{ref:e => et.value = e,class:`text-14 min-w-14 c-#333 ${isHorizontal ? 'i-teenyicons:drag-vertical-solid cursor-col-resize' : 'i-teenyicons:drag-horizontal-outline cursor-row-resize'} ${lockItems ? 'is-locked' : ''}`}))
    return render;
}, { props: ['index', 'isHorizontal','lockBox','lockItems'], emits: ["pressed"] })

</script>

<template>
    <div ref="boxRef" :class="['box-resize', isHorizontal ? 'flex-row' : 'flex-col']" relative z-0 w-full h-full min-w-full min-h-full inline-flex lh-0>
            <template v-for="(node, i) in defaultNodes">
                <base-box :node="node" :index="i" :style="boxStyle[i]" @init="handleBoxInit"></base-box>
                <base-line v-if="i < len - 1" :index="i" :lock-box="lockBox" :lock-items="lockItems" :is-horizontal="isHorizontal"
                    @pressed="handlePressed"></base-line>
            </template>
        </div>
</template>

<style scoped>
.box-resize {
    >._line {
        color: #333;
        display: flex;
        align-items: center;
        justify-content: center;
        > :deep(i) {
            opacity: 0;
            &.is-locked {
                cursor:default;
            }
        }
        &:hover {
            box-shadow: 0px 0px 12px rgba(0, 0, 0, .52);
        }

        &.horizontal {
            min-width: 1px;
            height: 100%;
        }

        &.vertiacal {
            min-height: 1px;
            width: 100%;
        }
        &.is-locked {
            cursor:default;
        }
    }

    >.is-flex {
        flex: 1
    }

    &:hover{
        >._line{
            > :deep(i) {
                opacity: 1;
            }
        }
    }
}
</style>